import Vue from 'vue';
import get from 'lodash/get';
import unionBy from 'lodash/unionBy';

const isOperator = (value) => {
  const operators = [
    '=',
    '==',
    'eq',
    '!=',
    'neq',
    '<',
    'lt',
    '<=',
    'lte',
    '>',
    'gt',
    '>=',
    'gte',
    'includes',
    'startsWith',
    'endsWith',
  ];
  return typeof value === 'function' || operators.includes(value);
};

export const solveCondition = (condition, obj) => {
  if (Array.isArray(condition)) return condition.some((cond) => solveCondition(cond, obj));
  if (typeof condition === 'object') {
    return Object.keys(condition).every((key) => {
      let expression = condition[key];
      if (expression === undefined) return true;
      if (typeof expression !== 'object') expression = ['=', expression];
      if (Array.isArray(expression)) {
        if (!isOperator(expression[0])) {
          // 多选项过滤，暂时简单处理
          const sourceValue = get(obj, key);
          const targetValue = expression;
          return targetValue.includes(sourceValue);
        }
        expression = {
          operator: expression[0],
          value: expression[1],
        };
      }

      let sourceValue = get(obj, key);
      let targetValue = expression.value;
      if (targetValue === null) return true;
      if (expression.caseInsensitive) {
        sourceValue = typeof sourceValue === 'string'
          ? sourceValue.toLowerCase()
          : sourceValue;
        targetValue = typeof targetValue === 'string'
          ? targetValue.toLowerCase()
          : targetValue;
      }

      if (typeof expression.operator === 'function') return expression.operator(sourceValue, targetValue, expression);
      if (
        expression.operator === '='
        || expression.operator === '=='
        || expression.operator === 'eq'
      ) return sourceValue === targetValue;
      if (expression.operator === '!=' || expression.operator === 'neq') return sourceValue !== targetValue;
      if (expression.operator === '<' || expression.operator === 'lt') return sourceValue < targetValue;
      if (expression.operator === '<=' || expression.operator === 'lte') return sourceValue <= targetValue;
      if (expression.operator === '>' || expression.operator === 'gt') return sourceValue > targetValue;
      if (expression.operator === '>=' || expression.operator === 'gte') return sourceValue >= targetValue;
      if (expression.operator === 'includes') return String(sourceValue).includes(targetValue);
      if (expression.operator === 'startsWith') return String(sourceValue).startsWith(targetValue);
      if (expression.operator === 'endsWith') return String(sourceValue).endsWith(targetValue);
      throw new TypeError('Unknown operator in conditions!');
    });
  }
  throw new TypeError('Condition must be a Object or Array!');
};

/**
 * @example 作为简单的 query
 * const dataSource = new DataSource();
 * dataSource.query({
 *     paging,
 *     sorting,
 *     filtering,
 * }).then();
 *
 * @example 作为状态储存
 * const dataSource = new DataSource();
 * dataSource.filter();
 *
 */

const VueDataSource = Vue.extend({
  data() {
    return {
      data: [],
      cache: true,
      viewMode: 'page',
      paging: undefined, // @TODO
      sorting: undefined, // @readonly
      filtering: undefined, // @readonly
      // grouping: undefined,
      remote: false,
      remotePaging: false,
      remoteSorting: false,
      remoteFiltering: false,
      // remoteGrouping: false,
      // ------
      arrangedData: [], // 整理过的数据，用于缓存过滤和排序行为。比如多次获取分页的话，没有必要重新整理
      arranged: false,
      prependedData: [],
      dirty: false,
      originTotal: Infinity, // @readonly - originTotal 作为很重要的判断有没有加载完所有数据的依据
      initialLoaded: false,
      params: {},
    };
  },
  computed: {
    offset() {
      return this.paging ? (this.paging.number - 1) * this.paging.size : 0;
    },
    limit() {
      return this.paging ? this.paging.size : Infinity;
    },
    /**
     * 当前的总数，过滤后的分页数目
     */
    total() {
      return this.originTotal === Infinity
        ? this.data.length
        : this.originTotal;
    },
    totalPage() {
      if (!this.paging) return 1;
      const totalPage = Math.ceil(this.total / this.paging.size);
      if (totalPage === Infinity || totalPage === 0) return 1;
      return totalPage;
    },
    viewData() {
      if (this.paging) {
        if (this.viewMode === 'more') return this.arrangedData.slice(0, this.offset + this.limit);
        return this.arrangedData.slice(this.offset, this.offset + this.limit);
      } return this.arrangedData;
    },
  },
  watch: {
    data() {
      if (!this.rawTreeDisplayOnlyForNotice && (!this.remote || !this._load)) {
        this.arrange();
      }
    },
  },
  // paging, sorting, filtering 暂不用 watch
  created() {
    this.remote = !!this._load;
    // 传 data 为本地数据模式，此时已知所有数据
    if (!this.remote) {
      this.initialLoaded = true;
      this.originTotal = this.data.length;
      this.arrange();
    }
  },
  methods: {
    arrange() {
      let arrangedData = Array.from(this.data);
      if (this.isSimpleArray(arrangedData) && this.tag === 'u-table-view') {
        arrangedData = arrangedData.map((item) => ({ simple: item }));
      }
      if (this.remotePaging) return (this.arrangedData = arrangedData);

      const { filtering } = this;
      if (!this.remoteFiltering && filtering && Object.keys(filtering).length) {
        arrangedData = arrangedData.filter((item) => solveCondition(filtering, item));
        // // 前端筛选， 且无后端分页 时重置originTotal
        !this.remotePaging && (this.originTotal = arrangedData.length);
      }

      const { sorting } = this;
      if (!this.remoteSorting && sorting && sorting.field) {
        const { field } = sorting;
        const orderSign = sorting.order === 'asc' ? 1 : -1;
        if (sorting.compare) {
          arrangedData.sort((item1, item2) => sorting.compare(
            this.$at(item1, field),
            this.$at(item2, field),
            orderSign,
          ));
        } else {
          arrangedData.sort((item1, item2) => this.defaultCompare(
            this.$at(item1, field),
            this.$at(item2, field),
            orderSign,
          ));
        }
      }

      this.arrangedData = arrangedData;
    },
    _process(data) {
      return data;
    },
    clearLocalData() {
      this.data = [];
      this.arrangedData = [];
      this.originTotal = Infinity; // originTotal 必须清空，否则空列表不会更新
      this.arranged = false;
      this.initialLoaded = false;
    },
    mustRemote(offset, newOffset) {
      return (
        !this.hasAllRemoteData(offset, newOffset) // 没有全部的后端数据
        || (this.params.hasOwnProperty('filtering') && this.remoteFiltering)
        || (this.params.hasOwnProperty('sorting') && this.remoteSorting)
      );
    },
    /**
     * 根据 viewData，是否还有数据
     * @param {Number} offset - 位置
     */
    hasMore(offset) {
      if (offset === undefined || offset === Infinity) offset = this.offset + this.limit;
      console.log(
        this.offset,
        this.limit,
        offset,
        this.prependedData.length,
        this.originTotal,
      );
      return offset < this.prependedData.length + this.originTotal;
    },
    /**
     * 是否还有后端数据
     * @param {Number} offset - 位置
     */
    hasAllRemoteData(offset, newOffset) {
      if (!this.remote) return true;
      if (!this.remotePaging) return this.data.length >= this.originTotal;

      offset += this.prependedData.length;
      newOffset += this.prependedData.length;
      for (let i = offset; i < newOffset; i++) if (!this.data[i]) return false;
      return true;
    },
    hasChanges() {
      return false;
    },
    defaultCompare(a, b, sign) {
      if (a === b) return 0;
      return a > b ? sign : -sign;
    },
    _getExtraParams() {
      return undefined;
    },
    slice(offset, newOffset) {
      return this.arrangedData.slice(offset, newOffset);
    },
    isSimpleArray(arr) {
      if (!Array.isArray(arr)) {
        return false; // 如果不是数组类型，则不满足条件，直接返回 false
      }
      return arr.every((item) => {
        return typeof item !== 'object'; // 使用 typeof 判断是否为简单数据类型
      });
    },
    // _load(params)
    load(offset, limit, newPageNumber) {
      if (offset === undefined) offset = this.offset;
      if (limit === undefined) limit = this.limit;
      let newOffset = offset + limit;

      const queryChanged = Object.keys(this.params).length;
      // 调用前端缓存数据
      if (!this.remote || (this.cache && !this.mustRemote(offset, newOffset))) {
        // 没有缓存数据或者有新的请求参数时，再尝试重新过滤和排序
        if (queryChanged) {
          this.arrange();
          this.params = {};
          if (this.paging) this.paging.number = 1;
          offset = 0;
          newOffset = limit;
        }
        return Promise.resolve(this.arrangedData.slice(offset, newOffset));
      }

      // 调用后端数据
      // 如果有新的 query 参数的变更，则清除缓存
      if (queryChanged) {
        this.clearLocalData();
        this.params = {};
        if (this.paging) this.paging.number = 1;
        offset = 0;
      }
      const paging = {
        offset: offset - this.prependedData.length,
        limit: this.limit,
        ...this.paging,
      };
      if (newPageNumber !== undefined) {
        paging.number = newPageNumber;
      }

      const params = {
        paging,
        sorting: this.sorting,
        filtering: this.filtering,
        ...this._getExtraParams(),
      };

      // 支持 JDL
      if (this.paging) {
        params.page = params.paging.number;
        params.start = params.paging.offset;
        params.size = params.paging.size;
      }
      if (this.sorting && this.sorting.field) {
        params.sort = params.sorting.field;
        params.order = params.sorting.order;
      }

      const extraParams = this._getExtraParams();

      if (!this._load || typeof this._load !== 'function') return;

      return this._load(params, extraParams).then((result) => {
        this.initialLoaded = true;
        // 支持 JDL
        if (result instanceof Object) {
          if (result.hasOwnProperty('list') && result.hasOwnProperty('total')) {
            result.data = result.list;
          } else if (
            result.hasOwnProperty('totalElements')
            && result.hasOwnProperty('content')
          ) {
            result.total = result.totalElements;
            result.data = result.content;
          }
        }
        if (!this.remotePaging) {
          // 没有后端分页，认为是全部数据
          if (result instanceof Array) {
            // 只返回数组，没有 total 字段
            if (!result.length) this.originTotal = result.length;
            else this.data = this._process(result);
          } else if (result instanceof Object) {
            // 返回 { total, data }
            this.originTotal = result.total;
            this.data = this._process(result.data);
          } // 否则什么都不做

          this.arrange();
          return this.arrangedData.slice(offset, newOffset);
        }
        let partialData;

        if (result instanceof Array) {
          // 只返回数组，没有 total 字段
          partialData = this._process(result);
          if (!result.length) {
            // 没有数据了，则表示最后一次加载，记录下总数
            this.originTotal = this.data.length;
          }
        } else if (result instanceof Object) {
          // 返回 { total: boolean, data: Array<item> } 或 { last: boolean, data: Array<item> }
          if (result.total !== undefined) this.originTotal = result.total;
          else if (result.last) this.originTotal = this.data.length;
          partialData = this._process(result.data);
        } // 否则什么都不做

        if (limit === Infinity) {
          this.data = partialData;
          this.arrange();
          return partialData;
        }
        for (let i = 0; i < limit; i++) {
          const item = partialData[i];
          //   this.data.push(item);
          if (item) this.data[offset + i] = item;
        }

        this.arrange();
        return partialData;
      });
    },
    loadMore() {
      if (!this.hasMore()) return Promise.resolve([]);

      const newPageNumber = this.paging.number + 1;
      return this.load(this.offset + this.limit, undefined, newPageNumber).then(
        () => (this.paging.number = newPageNumber),
      );
    },
    reload() {
      if (!this._load || typeof this._load !== 'function') return;
      this.clearLocalData();
      this.load();
    },
    page(paging) {
      this.paging = paging;
    },
    sort(sorting) {
      this.sorting = sorting;
      this.params.sorting = sorting;
    },
    filter(filtering) {
      this.filtering = filtering;
      this.params.filtering = filtering;
    },
    // query(params) {
    //     this.params = params;
    //     return this;
    // },
    prepend(item) {
      this.data.unshift(item);
      this.prependedData.unshift(item);
      this.arrange();
    },
    add(item) {
      this.data.push(item);
      this.arrange();
    },
    get() {
      // 获取某一项
    },
    update() {
      // 更新某一项
    },
    remove() {
      // 删除某一项
    },
    save() {
      // 保存
    },
  },
});

function DataSource(options) {
  const data = {};
  const methods = {};

  Object.keys(options).forEach((key) => {
    const option = options[key];
    if (typeof option === 'function') methods[`_${key}`] = option;
    else data[key] = option;
  });

  // if (options.data)
  //     data.data = methods._process ? methods._process(options.data) : Array.from(options.data);

  VueDataSource.call(this, {
    data() {
      return data;
    },
    methods,
  });
}

DataSource.prototype = Object.create(VueDataSource.prototype);
// DataSource.prototype.constructor = DataSource;

export default DataSource;
